import { GpEcsWorld } from "../GpEcsWorld";
import { Sglt } from "../SgltDefine";
import { MathUtils, Rectangle, Vect3 } from "../../../common/MathUtils";
import ecs, { EcsComponent, EcsEntity, EcsEntityGroup} from "ecs-ts";
import { CommonSystem } from "./CommonSystem";
import { cure, getDistance, isHeroInSpecialState, makeDamage, matchFindTargetConditionList, onTriggerLogic } from "./battle/Utils";
import { BattleSystem, CureEventInfo, DamageEventInfo } from "./battle/BattleSystem";
import { MoveSystem } from "./MoveSystem";
import { GpEventDef } from "../GpEventDef";
import { GpCfg } from "../GpCfgDef";
import { Comp } from "../CompDef";
import { EActionLogicState, HeroActionLogic, EHeroLogicType, HeroActionEventData, PlayEffEventData, EHeroAttri, EHeroSpecialState, EHeroAttriModifyType, EHeroAttriOperationType, HeroLogic } from "../GpDef";
import { gg } from "../../../../Game";

export class HeroSystem extends ecs.EcsSystem<GpEcsWorld> {
    tempVec3 = new Vect3()
    uiInfo: Sglt.UiInfo
    worldInfo: Sglt.WorldInfo
    deadGroup: EcsEntityGroup = null

    constructor(world: GpEcsWorld, defaltGroupComps: (new () => EcsComponent)[] = [Comp.Hero, Comp.Battle.Alive]) {
        super(world, defaltGroupComps);
        this.uiInfo = this.world.getSingleton(Sglt.UiInfo)
        this.worldInfo = this.world.getSingleton(Sglt.WorldInfo)
        this.deadGroup = this.world.getGroupByClz(Comp.Hero, Comp.Battle.Dead)

    }


    getMyHero() {
        return this.defaultGroup.entities.find((entity) => entity.component(Comp.Force).value == 0)
    }

    update(): void {

        this.checkAction()

        this.checkDeadHero()
    }

    tempRect: Rectangle = new Rectangle()
    tempQueryResult: EcsEntity[] = []

    /**寻找攻击目标 */
    findAttTarget(entity: EcsEntity, action: Comp.HeroAction) {
        const force = entity.component(Comp.Force)
        let target = null
        let findEnemyRange = action.findTargetRange
        this.tempQueryResult.length = 0
        const transform = entity.component(Comp.Transform)
        const quadTree = this.world.system(CommonSystem).quadTree
        MathUtils.getRectInDirection(transform.pos, { x: 0, y: 0, z: 0 }, findEnemyRange * 2, findEnemyRange * 2, this.tempRect)
        this.tempQueryResult = quadTree.query(this.tempRect, this.tempQueryResult)
        let lastDistance = 0

        this.tempQueryResult.forEach((queryItemEntity) => {
            if (queryItemEntity.component(Comp.Battle.Alive) && matchFindTargetConditionList(queryItemEntity, action.targetConditionList)) {
                const targetTransform = queryItemEntity.component(Comp.Transform)
                const targetPos = targetTransform.pos
                const targetDistance = getDistance(transform, targetTransform)

                if (!target) {
                    target = queryItemEntity
                    lastDistance = targetDistance
                } else if (targetDistance < lastDistance) {
                    target = queryItemEntity
                    lastDistance = targetDistance
                }
            }
        })

        return target
    }


    setAction(entity: EcsEntity, action: Comp.HeroAction, actionId: number, skilId = 0) {

        ecs.EcsComponent.resetComp(action, Comp.HeroAction)

        if (!actionId) {
            return
        }

        const actionCfg = gg.cfgById(GpCfg.Action, actionId)
        if (entity.id == 10000) {
            let a = 1
        }
        const attSpeed = Comp.Battle.Attri.getEntityAttriValue(entity, EHeroAttri.attSpeed)
        action.duration = actionCfg.duration * 1000 / attSpeed
        action.id = actionCfg.id
        action.targetConditionList = GpCfg.Action.toFindTargetConditions(actionCfg)
        action.logicList = GpCfg.Action.toLogics(actionCfg)
        action.nextActionId = actionCfg.nextActionId
        action.range = entity.component(Comp.Battle.BattleInfo).attRange
        action.startTimeMs = 0
        action.skillId = skilId
        action.needTarget = actionCfg.needTarget
    }
    checkDeadHero() {
        this.deadGroup.forEach((entity) => {
            const dead = entity.component(Comp.Battle.Dead)
            if (dead.startTimeMs + dead.durationMs < this.world.elapsedTimeMs) {
                this.world.removeComponent(entity,Comp.Battle.Dead)
                this.world.addComponent(entity,Comp.Battle.Alive)
                this.world.removeEntity(entity.id)
            }
        })
    }
    checkAction() {
        this.defaultGroup.forEach((entity) => {

            const hero = entity.component(Comp.Hero)
            const force = entity.component(Comp.Force)

            const action = entity.component(Comp.HeroAction)
            const transform = entity.component(Comp.Transform)
            const move = entity.component(Comp.Move)


            if (!action) {
                return
            }
            /**眩晕状态 */
            const isStun = isHeroInSpecialState(this.world, entity, EHeroSpecialState.stun)
            /**有移动方向，说明在操作摇杆，只移动不做任何动作 */
            const moveTargetDirectionMag = Vect3.mag(move.targetDirection)
            if (moveTargetDirectionMag > 0 || isStun) {
                this.setAction(entity, action, 0)
                return
            }

            let target: EcsEntity = null
            /**动作需要目标 */
            if (action.needTarget) {
                target = this.world.getEntity(action.targetId)

                /**满足一些条件才重新寻找目标 */
                if (!action.targetId && !target && this.world.elapsedTimeMs - action.lastFindTargetTimeMs >= action.findTargetInterval && action.logicList.find(i => i.state == EActionLogicState.doing)) {

                    target = this.findAttTarget(entity, action)

                    if (target) {
                        action.targetId = target.id
                        action.findTargetInterval = 0
                    } else {
                        action.findTargetInterval = Math.min(action.findTargetInterval + 100, action.maxFindTargetInterval)
                    }
                    action.lastFindTargetTimeMs = this.world.elapsedTimeMs


                }



                if (target) {
                    const targetTransform = target.component(Comp.Transform)

                    const distance = getDistance(transform, targetTransform)
                    if (distance <= action.range) {
                        this.tryDoAction(entity, action, target)

                        if (!move.hasForceMoveTargetPos) {
                            Vect3.set(move.targetPos, targetTransform.pos)
                            move.hasMoveTargetPos = false

                        }

                    } else if (!move.hasMoveTargetPos) {
                        this.world.system(MoveSystem).tryMoveTo(entity, transform, move, targetTransform.pos)

                    }


                } else {
                    if (action.targetId) {
                        // action.targetId = 0
                        move.hasMoveTargetPos = false
                        Vect3.set(move.targetPos, Vect3.ZERO)

                    }
                }
            } else {
                this.tryDoAction(entity, action, target)

            }


            /**检查是否结束 */
            if (action.startTimeMs) {
                const attFinisheTime = action.startTimeMs + action.duration


                if (this.world.elapsedTimeMs > attFinisheTime) {
                    action.playing = false
                    gg.eventTarget.emit(GpEventDef.onActionEnd, new HeroActionEventData(entity, action, target))
                    const actionCfg = gg.cfgById(GpCfg.Action, action.id)
                    this.setAction(entity, action, action.nextActionId)
                    /**如果目标还活着，继续对该目标执行动作 */
                    if (target && actionCfg.keepTarget && this.world.getEntity(target.id)) {
                        action.targetId = target.id
                    }
                }
            }
        })
    }

    tryDoAction(entity: EcsEntity, action: Comp.HeroAction, target: EcsEntity) {

        if (action.playing) {
            const attFinisheTime = action.startTimeMs + action.duration
            action.logicList.filter((i) => {
                const attAnimTriggerTime = action.startTimeMs + action.duration * i.triggerTimeRatio
                return i.state == EActionLogicState.doing && this.world.elapsedTimeMs >= attAnimTriggerTime
            }).forEach(
                i => {
                    onTriggerLogic(this.world, entity, i)
                    i.state = EActionLogicState.finished
                }

            )
            // if (this.world.elapsedTimeMs > attFinisheTime) {
            //     action.playing = false
            //     gg.eventTarget.emit(GpEventDef.onActionEnd, new HeroActionEventData(entity, action, target))
            //     const actionCfg = gg.cfgById(GpCfg.Action, action.id)
            //     this.setAction(entity, action, action.nextActionId)
            //     /**如果目标还活着，继续对该目标执行动作 */
            //     if (actionCfg.keepTarget && this.world.getEntity(target.id)) {
            //         action.targetId = target.id
            //     }
            // }
            // return
        } else {
            if (action.id) {
                // const targetTransform = target.component(Comp.Transform)
                // const transform = entity.component(Comp.Transform)
                // const direction = Vec3.subtract(this.tempVec3, targetTransform.pos, transform.pos)
                // const angle = Vec3.angle(direction, transform.orientation)
                // const attAngleDgree = action.needAngleDgree
                // //如果角度>attAngleDgree度，不攻击
                // if (angle > Math.PI / (180 / attAngleDgree)) {
                //     return
                // }
                action.playing = true
                action.startTimeMs = this.world.elapsedTimeMs
                if (action.skillId) {
                    const skill = entity.component(Comp.Battle.OwnSkills).skills.find(i => i.id == action.skillId)
                    if (skill) {
                        const cfg = gg.cfgById(GpCfg.Skill, skill.id)
                        skill.nextCanUseTimeMs = this.world.elapsedTimeMs + cfg.cd * 1000
                    }
                }
                //console.log("tryDoAction ", action.id);

                gg.eventTarget.emit(GpEventDef.onActionStart, new HeroActionEventData(entity, action, target))
            }
        }
    }


}

